﻿<?
	class Dictionary
	{
		protected $table;
		
		function __construct($table)
		{
			$this->table = strtolower('dic_' . $table);			
		}
		
		public function create($data = array())
		{			
			$meta = new EntityMeta('DefaultDictionary');
			$sql = $meta->getSql($this->table);
            $con = new Connection();
			
			$con->query($sql)->close();
			$this->updateFields($data);
		}
		
		public function drop()
		{
			$this->query()->drop();
		}
		
		public function clear()
		{
			$this->query()->clear();
		}
		
		public function rename($name)
		{
			$name = strtolower('dic_' . $name);
			
			if($name == $this->table)
			{
				return;
			}
			
			$con = new Connection();
			$sql = "rename table `$this->table` to `$name`";
			
			$con->query($sql)->close();
			
			$this->table = $name;
		}
		
		public function getMeta()
		{
			$fields = array();
			$pattern = '/([a-z]+)(\(([0-9]+)\))?/';
			$types = array(
				'tinyint(1)' => 'boolean'
			);
			
			foreach($this->getFields() as $f)
			{				
				if(isset($types[$f['type']]))
				{
					$type = $types[$f['type']];
					$length = 0;
				} 
				else 
				{
					preg_match($pattern, $f['type'], $m);
					
					$type = $m[1];
					$length = isset($m[3]) ? $m[3] : 0;				
				}
				
				$code = $f['code'];
				
				$fields[] = array(
					'type' => $type,
					'length' => $length,
					'def' => $f['def'],
					'code' => $code,
					'old' => $code
				);
			}
			
			return $fields;
		}

		public function getFields()
		{
			$query = new Query('information_schema.columns');
			
			$query->field('column_name', 'code')
				  ->field('column_default', 'def')
				  ->field('column_type', 'type');			
			
			$query->where(
				array(
					'eq' => array(
						array('table_name', $this->table),
						array('table_schema', App::get('db_name'))
					),
					'not' => array('code', array('id', 'parent_id'), 'and')
				)
			);
			
			return $query->results();
		}
		
		public function updateFields($data)
		{
			$fields = $this->getFields();
			$toDrop = array();
			$toCreate = array();
			$toUpdate = array();
			
			foreach($data as $field)
			{
				$isNew = true;
				
				if(isset($field->old))
				{
					$old = strtolower($field->old);
					
					foreach($fields as $i=>$f)
					{
						if($old == strtolower($f['code']))
						{
							if($this->checkModified($field, $f))
							{												
								$toUpdate[] = "CHANGE `$old`" . $this->prepareField($field);
							}
							
							$isNew = false;
							
							unset($fields[$i]);
							break;
						}
					}
				}
				
				if($isNew)
					$toCreate[] = "ADD" . $this->prepareField($field);
			}
			
			foreach($fields as $field)
				$toDrop[] = sprintf("DROP `%s`", $field['code']);
			
			$con = new Connection();
			$pre = sprintf('ALTER TABLE `%s` ', $this->table);
			
			if(count($toUpdate)) $con->query($pre . join(',', $toUpdate));			
			if(count($toDrop)) $con->query($pre . join(',', $toDrop));			
			if(count($toCreate)) $con->query($pre . join(',', $toCreate));
			
			$con->close();
		}
				
		private function query()
		{
			return new Query($this->table);
		}
		
		private function prepareField($field)
		{
			$types = array('text', 'boolean');
			$length = isset($field->length) ? intVal($field->length) : 0;
			$name = strtoupper($field->code);
			$type = $field->type;
			$type = in_array($type, $types) ? $type : "$type($length)";
			$def = isset($field->def) && !empty($field->def) ? $field->def : null;
				
			if($type == 'boolean')
			{
				$def = (bool)$def;
			}
			
			$def = empty($def) ? "DEFAULT NULL" : "DEFAULT '$def'";
			
			return " `$name` $type $def ";
		}
		
		private function checkModified($field, $old)
		{
			$types = array('text', 'boolean');
			$length = isset($field->length) ? intVal($field->length) : 0;
			$def = isset($field->def) ? $field->def : null;
			$type = $field->type;
			
			switch($type)
			{				
				case 'text': break;				
				case 'boolean': $type = 'tinyint(1)'; break;	
				default: 
					$type = in_array($type, $types) ? $type : "$type($length)"; 
					break;					
			}		
			
			return (
				strtolower($field->code) != strtolower($old['code']) ||
				strtolower($type) != strtolower($old['type']) ||
				$def != $old['def']
			);
		}
	}
?>